/*************************************************************
* DS_TASK.CPP
*
* Task system 
*************************************************************/
#include <ap\ap_comm.h>
#include <ap\settings\ds_settings.h>
#include <ds\ds_task.h>
#include <ds\ds_event_mgr.h>

namespace gts {

SYSTEM taskSystem;
dsVECTOR<SYSTEM::CREATE_INFO> SYSTEM::taskCreators;

int TASK::GetNextID() 
{
   static int nextID = 1;
   return nextID++;
}

int TASK::GetReadyEventID()
{
   static int e = gEventMgr->RegisterEvent("OnTaskReady_Unnamed");
   return e;
}

TASK::TASK() 
{ 
   id = GetNextID(); 
   state = TS_INITED;
}

void TASK::Start()
{
   if (state == TS_INITED) {
      state = TS_WAITING;
   }
}

/*************************************************************
* TASK::Finish()
* 
*************************************************************/
void TASK::Finish ()
{
   if ((state == TS_INITED) || (state == TS_WAITING)){
      state = TS_FINISHED;
   } else {
      // Wait think to complete task
      Cancel();
   }
}

void SYSTEM::Register(dsSTRID name, TaskCreator creator)
{
   taskCreators.InsertSorted(CREATE_INFO(name, creator));
}

TASK_PTR SYSTEM::Add(dsSTRID name, dsPARAM_LIST &params, bool startImmediately /* = false */)
{
   int idx = taskCreators.Find(name);
   if (idx != -1) {
      TASK_PTR p(taskCreators[idx].val(params));
      taskList.PushBack(p);
      if (startImmediately) {
         TryToStart(p);
      }
      return p;
   }

   return TASK_PTR(NULL);
}

TASK_PTR SYSTEM::Add(TASK* newTask, bool startImmediately /* = false */)
{
   STRONG_ASSERT(newTask);

   TASK_PTR tPtr(newTask);
   taskList.PushBack(tPtr);

   if (startImmediately) {
      TryToStart(tPtr);
   }
   return tPtr;
}

void SYSTEM::TryToStart(TASK_PTR &p)
{
   STRONG_ASSERT((p->state == TS_WAITING) || (p->state == TS_INITED));
   if (p->CanStart()) {
      p->state = TS_PROCESSING;
      p->Execute();
   }               
}

void SYSTEM::Think()
{
   for (TASK_ITERATOR iter = taskList.Begin(); !iter.IsDone(); ++iter) {
      TASK_PTR p = (*iter);
      switch (p->state) {
         case TS_WAITING:
            {
               TryToStart(p);
               break;
            }
         case TS_PROCESSING:
            {
               if (! p->IsReady()) {
                  p->Think();
               }
               if (p->IsReady()) {
                  p->state = TS_FINISHED;
                  gEventMgr->SignalEvent(p->GetReadyEventID());
               }
               break;               
            }
         default:
            break;
      }
   }

   TASK_ITERATOR iter = taskList.Begin(); 
   while (!iter.IsDone()) {
      TASK_PTR p = (*iter);
      if (p->state == TS_FINISHED) {
         iter = taskList.Erase(iter);
      } else {
         ++iter;
      }
   }
}

} // namespace

